#include"Inference.h"
Inference::Inference(Grammar& g):grammar(g){
  //Inference::grammar=g;
  Grammar_Num=g.grammar_num();
  Token_Num=g.token_num();
  b_count.resize(Grammar_Num);
  e_count.resize(Grammar_Num);
  for(int i=0;i<Grammar_Num;i++){
    b_count[i].resize(Grammar_Num*Grammar_Num);
    e_count[i].resize(Token_Num);
  }
}

void Inference::beforeinference(){
  for(int i=0;i<Grammar_Num;i++)grammar.getGrammarSymbol(i).resetchanges();
  for(int i=0;i<Grammar_Num;i++)
    for(int j=0;j<Token_Num;j++)
      e_count[i][j]=0;
  for(int i=0;i<Grammar_Num;i++)
    for(int j=0;j<b_count[i].size();j++)
      b_count[i][j]=0;
}

bool Inference::isconverge(){
  double eps=Config::getdouble("eps");
 for(int i=0;i<Grammar_Num;i++){
   if(grammar.getGrammarSymbol(i).last_change()>eps)return false;
 }
 return true;
}

void Inference::updategrammar(){
  for(int i=0;i<Grammar_Num;i++){
    double total_e=0,total_b=0;
    for(int j=0;j<e_count[i].size();j++)total_e+=e_count[i][j]*Config::getdouble("scale");
    for(int j=0;j<b_count[i].size();j++)total_b+=b_count[i][j]*Config::getdouble("scale");
    
    total_e+=Config::getdouble("alphaE");
    total_b+=Config::getdouble("alphaB");
    //total_e=total_e*Config::getdouble("scale");
    //total_b=total_b*Config::getdouble("scale");
    GrammarSymbol& tempg=grammar.getGrammarSymbol(i);

    double temp_e,temp_b;
    temp_e=Config::getdouble("alphaE")/Token_Num;
    temp_b=Config::getdouble("alphaB")/(Grammar_Num*Grammar_Num);
    if(total_e>0){
      for(int j=0;j<e_count[i].size();j++)
	//if(e_count[i][j]>0)
	tempg.setemission(j,exp(digamma(temp_e+e_count[i][j]*Config::getdouble("scale"))-digamma(total_e)));
	//else
	  //tempg.setemission(j,Config::getdouble("smooth"));
    }
    
    //std::cout<<total_e<<" "<<total_b<<std::endl;
    //std::cout<<grammar.getGrammarSymbol(i).last_change()<<" in updategrammar"<<std::endl;

    if(total_b>0)
      for(int j=0;j<Grammar_Num;j++)
	for(int k=0;k<Grammar_Num;k++)
	  tempg.setbinary(j,k,exp(digamma(temp_b+b_count[i][tempg.twoD2oneD(j,k)]*Config::getdouble("scale"))-digamma(total_b)));
    
    
    if(total_e>0)
	tempg.settype_e(exp(digamma(total_e+Config::getdouble("alphaT")/2)-digamma(Config::getdouble("alphaT")+total_e+total_b)));
    //else
	//tempg.settype_e(Config::getdouble("smooth"));
    if(total_b>0)
	tempg.settype_b(exp(digamma(total_b+Config::getdouble("alphaT")/2)-digamma(Config::getdouble("alphaT")+total_b+total_e)));
     //else
       //tempg.settype_b(Config::getdouble("smooth"));
    
 }
}
void Inference::printcount(){
  for(int i=0;i<Token_Num;i++)
    std::cout<<e_count[1][i]<<" ";
  std::cout<<std::endl;
}
void Inference::insideoutside(std::vector<int> sentence){
  int length=sentence.size();
  double inside[length][length][Grammar_Num];
  double outside[length][length][Grammar_Num];
  for(int i=0;i<length;i++)
    for(int j=0;j<length;j++)
      for(int k=0;k<Grammar_Num;k++){
	inside[i][j][k]=0;
        outside[i][j][k]=0;
      }

  for(int i=0;i<length;i++)
    for(int j=0;j<Grammar_Num;j++){
      inside[i][i][j]=grammar.getGrammarSymbol(j).getemission(sentence[i]);
    }
  for(int j=0;j<Grammar_Num;j++)outside[0][length-1][j]=0;
  outside[0][length-1][0]=1;
               
  /*
   * calculate inside
   */
               
  for(int k=1;k<length;k++)
    for(int i=0;i+k<length;i++)
      for(int z=0;z<Grammar_Num;z++){
	for(int j=i;j<i+k;j++)
	  for(int zl=0;zl<Grammar_Num;zl++)
	    for(int zr=0;zr<Grammar_Num;zr++){
	      inside[i][i+k][z]=inside[i][i+k][z]+
		(grammar.getGrammarSymbol(z).getbinary(zl,zr))*
		inside[i][j][zl]*inside[j+1][i+k][zr];
	    }
      }
               
  /*             
   * calculate outside
   */
               
  for(int k=length-1;k>=0;k--)
    for(int i=0;i+k<length;i++)
      for(int z=0;z<Grammar_Num;z++)
	for(int zout=0;zout<Grammar_Num;zout++)
	  for(int zin=0;zin<Grammar_Num;zin++){
	    for(int j=i+k+1;j<length;j++)
	      outside[i][i+k][z]=outside[i][i+k][z]+
		grammar.getGrammarSymbol(zout).getbinary(z,zin)*
		inside[i+k+1][j][zin]*
		outside[i][j][zout];
	    for(int j=0;j<i;j++)
	      outside[i][i+k][z]=outside[i][i+k][z]+
		grammar.getGrammarSymbol(zout).getbinary(zin,z)*
		inside[j][i-1][zin]*
		outside[j][i+k][zout];
	  }
               
  double total=inside[0][length-1][0];
  if(total==0){
    std::cerr<<" sentence probability zero ! egnore this sentence! "<<std::endl;
    return ;
  }
  double scale=1/total;
  
  for(int z=0;z<Grammar_Num;z++)
    for(int zl=0;zl<Grammar_Num;zl++)
      for(int zr=0;zr<Grammar_Num;zr++){
	double temp=0;
	for(int i=0;i<length;i++)
	  for(int k=i;k<length;k++)
	    for(int j=k+1;j<length;j++)
	      temp=temp+outside[i][j][z]*scale*
		grammar.getGrammarSymbol(z).getbinary(zl,zr)*
		inside[i][k][zl]*
		inside[k+1][j][zr];
	b_count[z][grammar.getGrammarSymbol(z).twoD2oneD(zl,
	    zr)]=b_count[z][grammar.getGrammarSymbol(z).twoD2oneD(zl, zr)]+temp;
      }
  for(int z=0;z<Grammar_Num;z++)
    for(int a=0;a<Token_Num;a++){
      double temp=0;
      for(int i=0;i<length;i++)if(sentence[i]==a)
	temp=temp+outside[i][i][z]*scale*inside[i][i][z];
      e_count[z][a]=e_count[z][a]+temp;
    }
}
